import path from "path";
import fileSys from "fs";
import URL from "url";
import { app, remote } from "electron";
import {parseURL, requestText} from "./httpFunc";
import {getAppObj} from "./appFunc";
import {MangaSite} from "../class/MangaSite/MangaSite";
import http from "http";
import https from "https";

export function readFile(filename: string, encoding: string = "utf8"): Promise<string> {
    return new Promise<string>((resolve, reject) => {
        fileSys.readFile(filename, encoding, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

export async function writeFile(filename: string, data: any, encoding: string = "utf8"): Promise<void> {
    const dirname = path.dirname(filename);
    const dirExists = await exists(dirname);
    if (!dirExists) {
        await mkdir(dirname);
    }
    return new Promise<void>((resolve, reject) => {
        fileSys.writeFile(filename, data, encoding, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    });
}

export function exists(filename: string): Promise<boolean> {
    return new Promise<boolean>((resolve) => {
        fileSys.access(filename, (err) => {
            if (err) {
                resolve(false);
            } else {
                resolve(true);
            }
        });
    });
}

export function mkdir(filename: string): Promise<void> {
    return new Promise<void>((resolve, reject) => {
        fileSys.mkdir(filename, { recursive: true }, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    });
}

export function toPosix(pathname: string) {
    return pathname.replace(/\\/g, "/");
}

export async function copyImg(from: string, to: string) {
    from = toPosix(from);
    to = toPosix(to);
    const imgData = await readFile(from, "binary");
    const basedir = path.dirname(to);
    const existsDir = await exists(basedir);
    if (!existsDir) {
        await mkdir(basedir);
    }
    await writeFile(to, imgData, "binary");
    return getURLOf(to);
}

export function getURLOf(filePath: string) {
    let myApp = app;
    if (!myApp) {
        myApp = remote.app;
    }
    const relativePath = toPosix(path.relative(toPosix(path.dirname(myApp.getAppPath())), toPosix(filePath)));
    return URL.format({
        protocol: "akaba",
        pathname: relativePath,
        slashes: true,
    });
}

export function writeImgByBase64(imgName: string, data: string) {
    const base64DataMatch = data.match(/data:image\/png;base64,(.+)/);
    const base64Data = base64DataMatch[1];
    const buffer = new Buffer(base64Data, "base64");
    return writeFile(imgName, buffer, "buffer");
}

export function joinPath(...strList: string[]) {
    return path.join(...strList);
}

export function parsePath(filename: string) {
    return path.parse(filename);
}

export async function writeSpecialSiteFileFromNet(
    urlStr: string,
    siteId: MangaSite.TSiteId,
    originURL: string,
    local: string,
    encoding: string = "binary"
) {
    if (siteId === "DMZJ") {
        return writeDMZJFileFromNet(urlStr, originURL, local, encoding);
    } else {
        return writeFileFromNet(originURL, local, encoding);
    }
}

export function writeDMZJFileFromNet(
    urlStr: string,
    originURL: string,
    local: string,
    encoding: string = "binary"
) {
    const pathObj = parseURL(urlStr);
    const referURLMatch = pathObj.search.match(/(^|\?|&)header_refer=([^&]+)/);
    if (referURLMatch) {
        const headerRefer = referURLMatch[2];
        return writeFileFromNet(originURL, local, encoding, {
            headers: {
                Referer: headerRefer,
            },
        });
    }
    return writeFileFromNet(originURL, local, encoding);
}

export async function writeFileFromNet(
    urlStr: string,
    local: string,
    encoding: string = "binary",
    otherOptions: http.RequestOptions | https.RequestOptions = {}
) {
    const data = await requestText(urlStr, encoding, "GET", otherOptions);
    return writeFile(local, data, encoding);
}

export function getDirnameOf(pathname: string) {
    return path.dirname(pathname);
}

export function getAppDirPath() {
    return toPosix(path.dirname(getAppObj().getAppPath()));
}

export function readDir(dirname: string): Promise<string[]> {
    return new Promise<string[]>((resolve, reject) => {
        fileSys.readdir(dirname, (err, files) => {
            if (err) {
                reject(err);
            } else {
                resolve(files);
            }
        });
    });
}
